import fs from 'fs';
import { parse } from 'path';
import SVGIcons2SVGFontStream from 'svgicons2svgfont';
import defaultMetaProvider from 'svgicons2svgfont/src/metadata';
import log from 'fancy-log';
import chalk from 'chalk';

import { getAbsolutelyPath as getAbsolutelyPath } from '../utils/path.utils';
import { scanAllFileFrom } from '../utils/scan.utils';
import { ConverterOptions, ConverterResultModel, SVGFontConvertResultModel } from './types';
import { DefaultSVGConvertOptions, DefaultSVGMetadataOptions } from './constants';
import { compatibleSVGVariablesTransform } from '../transform/compatible-svg-variables.transform';

class SVGToSVGFontConverter {
    private convertOptions: SVGIcons2SVGFontStream.SvgIcons2FontOptions;

    constructor(private readonly options: ConverterOptions) {}

    private initConvertConfig(userConfig?: SVGIcons2SVGFontStream.SvgIcons2FontOptions) {
        this.convertOptions = Object.assign({}, DefaultSVGConvertOptions, userConfig);

        if (!this.convertOptions.metadataProvider) {
            this.convertOptions.metadataProvider = defaultMetaProvider(DefaultSVGMetadataOptions);
        }
    }

    public async convert(options?: SVGIcons2SVGFontStream.SvgIcons2FontOptions): Promise<SVGFontConvertResultModel> {
        return new Promise<SVGFontConvertResultModel>(async (reslove, reject) => {
            this.initConvertConfig(options);

            const convertResult: SVGFontConvertResultModel = {
                fontData: '',
                metaMapping: null,
            };

            const fontStream = new SVGIcons2SVGFontStream(this.convertOptions)
                .on('data', (chunk) => {
                    convertResult.fontData += chunk;
                })
                .on('end', async () => {
                    //const filePath = getFilePath(this.options?.outDir, this.convertOptions.fontName);
                    //await writeFileTo(filePath, fontData);

                    //console.log(`Path: ${filePath}`);
                    //log(chalk.bgGreen(`Congratulations, SVG Icon Font Generated.`));

                    reslove(convertResult);
                })
                .on('error', (err) => {
                    log(chalk.red('Oops, there are some error when convert. \n', err));

                    reject(err);
                });

            convertResult.metaMapping = await this.writeAllIconToFontStream(fontStream);

            fontStream.end();
        });
    }

    private writeAllIconToFontStream(fontStream: SVGIcons2SVGFontStream): Promise<ConverterResultModel> {
        const iconMetaData: ConverterResultModel = {};

        const path = getAbsolutelyPath(this.options.formDir);

        const filePaths = scanAllFileFrom(path);

        return new Promise((reslove, reject) => {
            filePaths.forEach((path, i) => {
                this.convertOptions.metadataProvider(path, (err, metadata) => {
                    if (err) {
                        reject(err);
                    }

                    iconMetaData[parse(path).name] = {
                        ...metadata,
                        unicode: metadata.unicode.map((unco) => unco.charCodeAt(0).toString(16)),
                    };

                    const iconStream = fs.createReadStream(path, 'utf-8');

                    const pipedIconStream = iconStream.pipe(compatibleSVGVariablesTransform());

                    (pipedIconStream as any).metadata = metadata;

                    fontStream.write(pipedIconStream, 'utf-8');

                    // last one, return success
                    if (i === filePaths.length - 1) {
                        reslove(iconMetaData);
                    }
                });
            });
        });
    }
}

export { SVGToSVGFontConverter };
